/*
 * Copyright (c) 2016, Freescale Semiconductor, Inc.
 * Copyright 2016-2020,2022-2023  NXP
 * All rights reserved.
 *
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

/*******************************************************************************
 * Includes
 ******************************************************************************/
#include "MyFreertos.h"
#include "fsl_flexcan.h"
#include "lwip/opt.h"
#include "fsl_adapter_gpio.h"
#include "fsl_debug_console.h"
#include "lwipopts.h"
#include "ping.h"
#include "lwip/netifapi.h"
#include "lwip/tcpip.h"
#include "netif/ethernet.h"
#include "ethernetif.h"
#include "qos_ethernetif.h"
#include "qos_ethernetif_priv.h"
#include "pin_mux.h"
#include "board.h"
#ifndef configMAC_ADDR
#include "fsl_silicon_id.h"
#endif
#include "fsl_phy.h"
#include "fsl_enet.h"
#include "fsl_phyrtl8201.h"
#include "fsl_phyrtl8211f.h"
#include "fsl_enet_qos.h"
#include "sbl_ota_flag.h"
#include "mvb.h"
#include "MIMXRT1176_cm7.h"
#include "sysflash.h"
#include "bootutil_priv.h"
#include "flash_map.h"

#include "flexspi_flash.h"
#include "sbl_ota_flag.h"
/*******************************************************************************
 * Definitions
 ******************************************************************************/
/* @TEST_ANCHOR */
/*! @brief Priority of the temporary lwIP initialization thread. */
#define INIT_THREAD_STACKSIZE 1024
#define INIT_THREAD_PRIO DEFAULT_THREAD_PRIO
phy_rtl8201_resource_t enet_phy_resourece;
phy_rtl8211f_resource_t enet_1g_phy_resourece;
phy_rtl8211f_resource_t enet_qos_phy_resourece;
static phy_handle_t enet_phyHandle,enet_1g_phyHandle,enet_qos_phyHandle;
struct netif enet_netif,enet_1g_netif,enet_qos_netif;
/*******************************************************************************
 * Code
 ******************************************************************************/
void BOARD_InitModuleClock(void)
{
    const clock_sys_pll1_config_t sysPll1Config = {
        .pllDiv2En = true,
    };
    CLOCK_InitSysPll1(&sysPll1Config);

    clock_root_config_t enet_rootCfg = {.mux = 4, .div = 10}; /* Generate 50M root clock. */
    CLOCK_SetRootClock(kCLOCK_Root_Enet1, &enet_rootCfg);
    clock_root_config_t enet_1g_rootCfg = {.mux = 4, .div = 4};       /* Generate 125M root clock. */
    CLOCK_SetRootClock(kCLOCK_Root_Enet2, &enet_1g_rootCfg);

    clock_root_config_t enet_qos_rootCfg = {.mux = 4, .div = 4}; /* Generate 125M root clock. */
    CLOCK_SetRootClock(kCLOCK_Root_Enet_Qos, &enet_qos_rootCfg);
    enet_qos_rootCfg.div = 10;
    CLOCK_SetRootClock(kCLOCK_Root_Enet_Timer3, &enet_qos_rootCfg); /* Generate 50M PTP REF clock. */
}
void IOMUXC_SelectENETClock(void)
{
    IOMUXC_GPR->GPR4 |= IOMUXC_GPR_GPR4_ENET_REF_CLK_DIR_MASK; /* 50M ENET_REF_CLOCK output to PHY and ENET module. */

    IOMUXC_GPR->GPR5 |= IOMUXC_GPR_GPR5_ENET1G_RGMII_EN_MASK; /* bit1:iomuxc_gpr_enet_clk_dir
                                                                 bit0:GPR_ENET_TX_CLK_SEL(internal or OSC) */
    IOMUXC_GPR->GPR6 |= IOMUXC_GPR_GPR6_ENET_QOS_RGMII_EN_MASK; /* Set this bit to enable ENET_QOS RGMII TX clock output
                                                                       on TX_CLK pad. */
}

void BOARD_ENETFlexibleConfigure(enet_config_t *config)
{
	config->miiMode = kENET_RgmiiMode;
    if(config->userData==&enet_netif)
    {
    	config->miiMode = kENET_RmiiMode;
    }
    else if(config->userData==&enet_1g_netif)
    {
    	config->miiMode = kENET_RgmiiMode;
    }
}
void ENET_QOS_EnableClock(bool enable)
{
    IOMUXC_GPR->GPR6 =
        (IOMUXC_GPR->GPR6 & (~IOMUXC_GPR_GPR6_ENET_QOS_CLKGEN_EN_MASK)) | IOMUXC_GPR_GPR6_ENET_QOS_CLKGEN_EN(enable);
}
void ENET_QOS_SetSYSControl(enet_qos_mii_mode_t miiMode)
{
    IOMUXC_GPR->GPR6 =
        (IOMUXC_GPR->GPR6 & (~IOMUXC_GPR_GPR6_ENET_QOS_INTF_SEL_MASK)) | IOMUXC_GPR_GPR6_ENET_QOS_INTF_SEL(miiMode);
}
static void MDIO_Init(void)
{
    (void)CLOCK_EnableClock(s_enetClock[ENET_GetInstance(ENET)]);
    ENET_SetSMI(ENET, CLOCK_GetRootClockFreq(kCLOCK_Root_Bus), false);
    (void)CLOCK_EnableClock(s_enetClock[ENET_GetInstance(ENET_1G)]);
    ENET_SetSMI(ENET_1G, CLOCK_GetRootClockFreq(kCLOCK_Root_Bus), false);
    CLOCK_EnableClock(s_enetqosClock[ENET_QOS_GetInstance(ENET_QOS)]);
	ENET_QOS_SetSMI(ENET_QOS, CLOCK_GetRootClockFreq(kCLOCK_Root_Bus));
}
static status_t Enet_MDIO_Write(uint8_t phyAddr, uint8_t regAddr, uint16_t data)
{
    return ENET_MDIOWrite(ENET, phyAddr, regAddr, data);
}
static status_t Enet_MDIO_Read(uint8_t phyAddr, uint8_t regAddr, uint16_t *pData)
{
    return ENET_MDIORead(ENET, phyAddr, regAddr, pData);
}
static status_t Enet1g_MDIO_Write(uint8_t phyAddr, uint8_t regAddr, uint16_t data)
{
    return ENET_MDIOWrite(ENET_1G, phyAddr, regAddr, data);
}
static status_t Enet1g_MDIO_Read(uint8_t phyAddr, uint8_t regAddr, uint16_t *pData)
{
    return ENET_MDIORead(ENET_1G, phyAddr, regAddr, pData);
}
static status_t EnetQos_MDIO_Write(uint8_t phyAddr, uint8_t regAddr, uint16_t data)
{
    return ENET_QOS_MDIOWrite(ENET_QOS, phyAddr, regAddr, data);
}
static status_t EnetQos_MDIO_Read(uint8_t phyAddr, uint8_t regAddr, uint16_t *pData)
{
    return ENET_QOS_MDIORead(ENET_QOS, phyAddr, regAddr, pData);
}
/*!
 * @brief Initializes lwIP stack.
 */
ip4_addr_t enet_netif_ipaddr, enet_netif_netmask, enet_netif_gw;
ip4_addr_t enet_1g_netif_ipaddr, enet_1g_netif_netmask, enet_1g_netif_gw;
ip4_addr_t enet_qos_netif_ipaddr, enet_qos_netif_netmask, enet_qos_netif_gw;
void EthInit()
{
    IOMUXC_SelectENETClock();

    GPIO_WritePinOutput(BOARD_INITPINS_ETHPHY_QOS_RST_B_GPIO, BOARD_INITPINS_ETHPHY_QOS_RST_B_GPIO_PIN, 0);
	GPIO_WritePinOutput(BOARD_INITPINS_ENET_RST_B_GPIO, BOARD_INITPINS_ENET_RST_B_GPIO_PIN, 0);
	GPIO_WritePinOutput(BOARD_INITPINS_ETHPHY_RST_B_GPIO, BOARD_INITPINS_ETHPHY_RST_B_GPIO_PIN, 0);
	SDK_DelayAtLeastUs(20000, CLOCK_GetFreq(kCLOCK_CpuClk));
	GPIO_WritePinOutput(BOARD_INITPINS_ETHPHY_QOS_RST_B_GPIO, BOARD_INITPINS_ETHPHY_QOS_RST_B_GPIO_PIN, 1);
	GPIO_WritePinOutput(BOARD_INITPINS_ENET_RST_B_GPIO, BOARD_INITPINS_ENET_RST_B_GPIO_PIN, 1);
	GPIO_WritePinOutput(BOARD_INITPINS_ETHPHY_RST_B_GPIO, BOARD_INITPINS_ETHPHY_RST_B_GPIO_PIN, 1);
	SDK_DelayAtLeastUs(60000, CLOCK_GetFreq(kCLOCK_CpuClk));

	EnableIRQ(ENET_1G_MAC0_Tx_Rx_1_IRQn);
	EnableIRQ(ENET_1G_MAC0_Tx_Rx_2_IRQn);
	NVIC_SetPriority(ENET_QOS_IRQn, ENET_QOS_PRIORITY);
    MDIO_Init();
    enet_phy_resourece.read  = Enet_MDIO_Read;
    enet_phy_resourece.write = Enet_MDIO_Write;
    enet_1g_phy_resourece.read  = Enet1g_MDIO_Read;
    enet_1g_phy_resourece.write = Enet1g_MDIO_Write;
    enet_qos_phy_resourece.read  = EnetQos_MDIO_Read;
    enet_qos_phy_resourece.write = EnetQos_MDIO_Write;
}
void LwipInit()
{
    ethernetif_config_t enet_config = {
        .phyHandle   = &enet_phyHandle,
        .phyAddr     = BOARD_ENET0_PHY_ADDRESS,
        .phyOps      = &phyrtl8201_ops,
        .phyResource = &enet_phy_resourece,
        .srcClockHz  = CLOCK_GetRootClockFreq(kCLOCK_Root_Bus),
    };
     ethernetif_config_t enet_1g_config = {
            .phyHandle   = &enet_1g_phyHandle,
            .phyAddr     = BOARD_ENET1_PHY_ADDRESS,
            .phyOps      = &phyrtl8211f_ops,
            .phyResource = &enet_1g_phy_resourece,
            .srcClockHz  = CLOCK_GetRootClockFreq(kCLOCK_Root_Bus),
        };
    qos_ethernetif_config_t enet_qos_config = {
            .phyHandle   = &enet_qos_phyHandle,
            .phyAddr     = 0x02U,
            .phyOps      = &phyrtl8211f_ops,
            .phyResource = &enet_qos_phy_resourece,
            .srcClockHz  = CLOCK_GetRootClockFreq(kCLOCK_Root_Bus),
        };
    /* Set MAC address. */
#ifndef configMAC_ADDR
    (void)SILICONID_ConvertToMacAddr(&enet_config.macAddress);
    (void)SILICONID_ConvertToMacAddr(&enet_1g_config.macAddress);
    enet_1g_config.macAddress[5]+=1;
    (void)SILICONID_ConvertToMacAddr(&enet_qos_config.macAddress);
    enet_qos_config.macAddress[5]+=2;
#endif
    IP4_ADDR(&enet_netif_ipaddr, ENETIPADDR0, ENETIPADDR1, ENETIPADDR2, ENETIPADDR3);
    IP4_ADDR(&enet_netif_netmask, ENETMASK0, ENETMASK1, ENETMASK2, ENETMASK3);
    IP4_ADDR(&enet_netif_gw, ENETGWADDR0, ENETGWADDR1, ENETGWADDR2, ENETGWADDR3);

//    IP4_ADDR(&enet_1g_netif_ipaddr, configIP_ADDR0, configIP_ADDR1, configIP_ADDR2+1, configIP_ADDR3);
//	IP4_ADDR(&enet_1g_netif_netmask, configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3);
//	IP4_ADDR(&enet_1g_netif_gw, configGW_ADDR0, configGW_ADDR1, configGW_ADDR2+1, configGW_ADDR3);

    IP4_ADDR(&enet_qos_netif_ipaddr, ENETQOSIPADDR0, ENETQOSIPADDR1, ENETQOSIPADDR2, ENETQOSIPADDR3);
	IP4_ADDR(&enet_qos_netif_netmask, ENETQOSMASK0, ENETQOSMASK1, ENETQOSMASK2, ENETQOSMASK3);
	IP4_ADDR(&enet_qos_netif_gw, ENETQOSGWADDR0, ENETQOSGWADDR1, ENETQOSGWADDR2, ENETQOSGWADDR3);

    tcpip_init(NULL, NULL);
    HAL_GpioPreInit();
    netifapi_netif_add(&enet_netif, &enet_netif_ipaddr, &enet_netif_netmask, &enet_netif_gw,
    		&enet_config, ethernetif0_init, tcpip_input);
	netifapi_netif_set_default(&enet_netif);
	netifapi_netif_set_up(&enet_netif);
//	while (ethernetif_wait_linkup(&enet_netif, 5000) != ERR_OK)
//	{
//		PRINTF("enet PHY Auto-negotiation failed. Please check the cable connection and link partner setting.\r\n");
//	}
    netifapi_netif_add(&enet_1g_netif, &enet_1g_netif_ipaddr, &enet_1g_netif_netmask, &enet_1g_netif_gw,
    		&enet_1g_config, ethernetif1_init, tcpip_input);
	netifapi_netif_set_default(&enet_1g_netif);
	netifapi_netif_set_up(&enet_1g_netif);
//	while (ethernetif_wait_linkup(&enet_1g_netif, 5000) != ERR_OK)
//	{
//		PRINTF("enet 1g PHY Auto-negotiation failed. Please check the cable connection and link partner setting.\r\n");
//	}
    netifapi_netif_add(&enet_qos_netif, &enet_qos_netif_ipaddr, &enet_qos_netif_netmask, &enet_qos_netif_gw,
    		&enet_qos_config, ethernetif2_init, tcpip_input);
	netifapi_netif_set_default(&enet_qos_netif);
	netifapi_netif_set_up(&enet_qos_netif);
//	while (qos_ethernetif_wait_linkup(&enet_qos_netif, 5000) != ERR_OK)
//	{
//		PRINTF("enet qos PHY Auto-negotiation failed. Please check the cable connection and link partner setting.\r\n");
//	}
}
static void StartTask(void *arg)
{
	EthInit();
	LwipInit();
	TaskCreat();
    vTaskDelete(NULL);
}
/*!
 * @brief Main function
 */
int main(void)
{
    BOARD_ConfigMPU();
    BOARD_InitPins();
    BOARD_BootClockRUN();
    BOARD_InitDebugConsole();
    BOARD_InitModuleClock();
    /* Initialize lwIP from thread */
    sfw_flash_init();
    if (sys_thread_new("StartTask", StartTask, NULL, INIT_THREAD_STACKSIZE, INIT_THREAD_PRIO) == NULL)
        LWIP_ASSERT("StartTask(): Task creation failed.", 0);
    vTaskStartScheduler();
    /* Will not get here unless a task calls vTaskEndScheduler ()*/
    return 0;
}
